package org.wangp.business.order.test

import cn.hutool.core.util.PageUtil
import com.alibaba.druid.filter.logging.Slf4jLogFilter
import com.alibaba.druid.filter.stat.StatFilter
import com.alibaba.druid.pool.DruidDataSource
import com.fasterxml.jackson.annotation.JsonFormat
import org.elasticsearch.index.query.QueryBuilders
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.annotation.Id
import org.springframework.data.elasticsearch.annotations.DateFormat
import org.springframework.data.elasticsearch.annotations.Document
import org.springframework.data.elasticsearch.annotations.Field
import org.springframework.data.elasticsearch.annotations.FieldType
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
import org.springframework.data.elasticsearch.core.query.Criteria
import org.springframework.data.elasticsearch.core.query.CriteriaQuery
import org.springframework.data.elasticsearch.core.query.Query
import org.springframework.data.elasticsearch.core.query.SimpleField
import org.springframework.jdbc.core.BeanPropertyRowMapper
import org.springframework.jdbc.core.ColumnMapRowMapper
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.support.JdbcUtils
import org.springframework.test.context.junit4.SpringRunner
import org.wangp.business.user.UserCenterApplication
import org.wangp.framework.core.config.AsyncConfiguration
import org.wangp.framework.core.util.camelCase
import org.wangp.framework.core.util.infoAny
import java.sql.ResultSet
import java.time.LocalDateTime
import java.util.concurrent.*
import javax.annotation.Resource
import kotlin.concurrent.thread
import kotlin.math.max
import kotlin.reflect.jvm.javaField

/**
 * @author wangpeng (๑•ᴗ•๑)
 * @since 2021/10/14 1:21
 */
@SpringBootTest(classes = [UserCenterApplication::class])
@RunWith(SpringRunner::class)
class LogTest {

	companion object {
		const val INDEX_NAME = "ftkjwlhypt_log"
		const val DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"
		val log: Logger = LoggerFactory.getLogger(LogTest::class.java)
	}

	private lateinit var jdbcTemplate: JdbcTemplate

	private lateinit var executor: Executor

	@Resource
	private lateinit var elasticsearchTemplate: AbstractElasticsearchTemplate


	@Before
	fun getDataSource() {
		jdbcTemplate = JdbcTemplate(DruidDataSource().apply {
			url =
				"jdbc:mysql://10.116.25.38:3306/ftkjwlhypt_pro?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&rewriteBatchedStatements=true"
			username = "kf_only"
			password = "!q@w#wjxx"
			isAsyncInit = true
			initialSize = Runtime.getRuntime().availableProcessors() / 2
			maxActive = Runtime.getRuntime().availableProcessors() / 2
			minIdle = Runtime.getRuntime().availableProcessors() / 2
			isUseUnfairLock = true
			validationQuery = "select 1 from dual"
			isTestWhileIdle = true
			name = "transport-log-DataSource"
			proxyFilters = listOf(Slf4jLogFilter(), StatFilter())
		})
		executor = ThreadPoolExecutor(
			Runtime.getRuntime().availableProcessors() / 2,
			Runtime.getRuntime().availableProcessors() / 2,
			30,
			TimeUnit.MINUTES,
			ArrayBlockingQueue(10000, true),
			ThreadFactory {
				val thread = thread(
					start = false
				) { it.run() }
				thread.name = "log-exec-${thread.id}"
				thread.uncaughtExceptionHandler = Thread.UncaughtExceptionHandler { t, e -> log.error(t.name, e) }
				thread
			})
	}

	@Test
	fun transport() {
		val count = jdbcTemplate.queryForObject("select count(1) from log", Int::class.java)!!
		val pageSize = 1000
		val page = PageUtil.totalPage(count, pageSize)
		val index = IndexCoordinates.of(INDEX_NAME)
		val tasks = arrayListOf<Runnable>()
		val indexOps = elasticsearchTemplate.indexOps(index)
		indexOps.delete()
		indexOps.create()
		for (i in 1..page) {
			tasks.add(Runnable {
				log.info("start $i")
				val startIndex = (i - 1) * pageSize
				val result = jdbcTemplate.query(
					"""
							select id, create_time, description, exception_detail, log_type, method, params, request_ip, time, username from log limit ?,?
						""".trimIndent(), BeanPropertyRowMapper(LogEntity::class.java), startIndex, pageSize
				)
				elasticsearchTemplate.save(result, index)
				log.info("end $i")
			})
		}
		CompletableFuture.allOf(*tasks.map {
			CompletableFuture.supplyAsync({ it.run() }, executor).exceptionally { t -> t.printStackTrace() }
		}.toTypedArray()).join()
	}

	@Test
	fun search() {
		val hits = elasticsearchTemplate.search(
			CriteriaQuery(Criteria.where(LogEntity::description.name).contains("规格")),
			LogEntity::class.java
		)
		log.infoAny(hits.toList())
	}

	@Document(indexName = INDEX_NAME, createIndex = true)
	data class LogEntity(
		@Id
		var esId: String? = null,
		@Field
		var lId: Long? = null,
		@Field(type = FieldType.Date, format = DateFormat.date_optional_time)
		@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_TIME_PATTERN, timezone = "GMT+8")
		var createTime: LocalDateTime? = null,
		@Field
		var description: String? = null,
		@Field
		var exceptionDetail: String? = null,
		@Field
		var logType: String? = null,
		@Field
		var method: String? = null,
		@Field
		var params: String? = null,
		@Field
		var requestIp: String? = null,
		@Field
		var time: Long? = null,
		@Field
		var username: String? = null
	)
}
